package com.hsd.netty.server.dispatcher;

import com.google.gson.Gson;
import com.hsd.netty.server.model.RequestObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * @author s.he
 * on 2020/6/1
 */
@Component
public class NettyHandlerDispatcher implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        if(applicationContext == null) {
            this.applicationContext = context;
        }
    }

    /**
     * 执行操作
     * @param requestObject
     * @return
     */
    public String execute(RequestObject requestObject) {
        Gson gson = new Gson();
        String className = requestObject.getClassName();
        String methodName = requestObject.getMethodName();
        String methodParams = requestObject.getMethodParams();
        String values = requestObject.getValues();

        /**
         * 构造方法参数
         */
        Object[] args = null;
        if(StringUtils.isNotEmpty(methodParams) && StringUtils.isNotEmpty(values)) {
            List<String> params = gson.fromJson(methodParams, List.class);
            Map<String, Object> paramMap = gson.fromJson(values, Map.class);
            args = new Object[params.size()];
            for(int i=0; i<params.size(); i++) {
                args[i] = paramMap.get(params.get(i));
            }
        }

        try {
            Class<?> aClass = Class.forName(className);
            Object service = applicationContext.getBean(aClass);
            Method[] declaredMethods = aClass.getDeclaredMethods();
            Method callMethod = null;
            for(Method method : declaredMethods) {
                if(StringUtils.equalsIgnoreCase(methodName, method.getName())) {
                    callMethod = method;
                    break;
                }
            }
            callMethod.setAccessible(false);
            return (String) callMethod.invoke(service, args);
        } catch (Exception e) {
            e.printStackTrace();
            return "ERROR";
        }
    }
}
